home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 2: Applications
/
Linux Cubed Series 2 - Applications.iso
/
circuits
/
pcb-1.000
/
pcb-1
/
pcb-1.3
/
fileselect.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-27
|
18KB
|
600 lines
/*
* COPYRIGHT
*
* PCB, interactive printed circuit board design
* Copyright (C) 1994,1995 Thomas Nau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contact addresses for paper mail and Email:
* Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
* Thomas.Nau@rz.uni-ulm.de
*
*/
static char *rcsid = "$Header: /sda4/users/nau/src/pcb/RCS/fileselect.c,v 2.1 1994/09/28 14:26:10 nau Exp nau $";
/* file select box
* some of the actions are local to this module
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <memory.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "global.h"
#include "data.h"
#include "dialog.h"
#include "error.h"
#include "fileselect.h"
#include "mymem.h"
#include "misc.h"
#include <X11/Shell.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/Scrollbar.h>
#include <X11/Xaw/Viewport.h>
/* ---------------------------------------------------------------------------
* some local types
*/
typedef struct /* a select box */
{
String Name; /* the name of the list widget */
Widget ViewportW, /* the listwidget and its manager */
ListW;
String *Entries; /* list of entries */
int Number, /* number of entries */
MaxNumber; /* maximum number */
XtCallbackProc Callback; /* notify callback */
XtPointer ClientData;
} SelectorType, *SelectorTypePtr;
/* ---------------------------------------------------------------------------
* some local prototypes
*/
static int CompareFunction(const void *, const void *);
static void AddEntryToList(char *, SelectorTypePtr);
static void FreeListEntries(SelectorTypePtr);
static int ChangeDirectory(char *);
static void SetInputWidget(String);
static void CB_CancelOrOK(Widget, XtPointer, XtPointer);
static void CB_Menu(Widget, XtPointer, XtPointer);
static void CB_Directory(Widget, XtPointer, XtPointer);
static void CB_File(Widget, XtPointer, XtPointer);
static void CB_Text(Widget, XtPointer, XtPointer);
static int FillLists(char *);
static int FillListsFromCommand(char *);
static int FillListsFromDirectory(char *);
static Widget CreateMenuFromPath(Widget, Widget, Widget, char *);
static Widget CreateSelector(Widget, Widget, Widget, SelectorTypePtr);
/* ---------------------------------------------------------------------------
* some local identifiers
*/
static Widget InputW, /* input field */
CurrentW; /* label (current directory) */
static int ReturnCode; /* returncode of buttons */
static String CurrentDir; /* current directory */
static Boolean LockCallback; /* used by CB_Text() */
static SelectorType DirectorySelector =
{ "directoryList", NULL,NULL,NULL, 0, 0, CB_Directory, &DirectorySelector };
static SelectorType FileSelector =
{ "fileList", NULL, NULL, NULL, 0, 0, CB_File, &FileSelector };
static DialogButtonType Buttons[] = {
{"defaultButton"," OK ",CB_CancelOrOK,(XtPointer) OK_BUTTON,NULL},
{"cancelButton","No/Cancel",CB_CancelOrOK,(XtPointer) CANCEL_BUTTON,NULL}};
/* ----------------------------------------------------------------------
* compare function for qsort() routine
* used to sort list by name
*/
static int CompareFunction(const void *P1, const void *P2)
{
return(strcmp(*((char **) P1), *((char **) P2)));
}
/* ---------------------------------------------------------------------------
* adds a new filename to the list;
* memory is allocated as needed;
* memory for the entry itself is already allocated
*/
static void AddEntryToList(char *Filename, SelectorTypePtr Selector)
{
/* allocate more memory */
if (Selector->Number >= Selector->MaxNumber)
{
Selector->MaxNumber += STEP_FILENAME;
Selector->Entries = MyRealloc(Selector->Entries,
Selector->MaxNumber *sizeof(char *), "AddEntryToList()");
memset(Selector->Entries +Selector->Number, 0,
STEP_FILENAME*sizeof(char *));
}
Selector->Entries[Selector->Number++] = Filename;
}
/* ---------------------------------------------------------------------------
* releases all memory that is allocated by list entries, not the list
* itself
*/
static void FreeListEntries(SelectorTypePtr Selector)
{
while (Selector->Number)
MyFree(&Selector->Entries[--Selector->Number]);
}
/* ----------------------------------------------------------------------
* changes current directory and prints an error message if failed
*/
static int ChangeDirectory(char *DirName)
{
if (chdir(DirName))
{
ChdirErrorMessage(DirName);
return(1);
}
return(0);
}
/* ---------------------------------------------------------------------------
* set contents of input widget to string
* replace old string
* this way resizes the widget if necessary
*/
static void SetInputWidget(String S)
{
Widget source = XawTextGetSource(InputW);
XawTextPosition last;
XawTextBlock block;
/* get last character position */
last = XawTextSourceScan(source, 0, XawstAll, XawsdRight, 1, True);
block.ptr = S;
block.firstPos = 0;
block.length = strlen(S);
block.format = FMT8BIT;
/* set 'lock' flag for next call of CB_Text() */
LockCallback = True;
/* replace contents by new string */
XawTextReplace(InputW, 0, last, &block);
XawTextSetInsertionPoint(InputW, block.length);
}
/* ---------------------------------------------------------------------------
* callback function for OK and cancel button
* also called via accelerators from a double click
* ClientData identifies the button
*/
static void CB_CancelOrOK(Widget W, XtPointer ClientData, XtPointer CallData)
{
ReturnCode = (int) ClientData;
}
/* ---------------------------------------------------------------------------
* callback function for rolldown menus
* directory name is passed as ClientData
*/
static void CB_Menu(Widget W, XtPointer ClientData, XtPointer CallData)
{
FillLists((char *) ClientData);
}
/* ---------------------------------------------------------------------------
* callback function for directory list
* gets current selection and updates the list widgets
*/
static void CB_Directory(Widget W, XtPointer ClientData, XtPointer CallData)
{
char newdir[MAXPATHLEN+1];
XawListReturnStruct *selected = XawListShowCurrent(W);
/* abort if nothing has been selected or if the selected thing is
* an external command
*/
if (selected->list_index == XAW_LIST_NONE ||
*selected->string == '|')
return;
/* create complete new path; update list */
sprintf(newdir, "%s/%s", CurrentDir, selected->string);
FillLists(newdir);
}
/* ---------------------------------------------------------------------------
* callback function for file list
* gets current selection and updates 'input widget'
*/
static void CB_File(Widget W, XtPointer ClientData, XtPointer CallData)
{
XawListReturnStruct *selected = XawListShowCurrent(W);
if (selected->list_index != XAW_LIST_NONE)
SetInputWidget(selected->string);
}
/* ---------------------------------------------------------------------------
* callback function for input text widget
* invalidates file selections whenever the buffer changes
* we have to prevent from unhighlighting the selection that has
* just updated the buffer by evaluating the 'LockCallback' flag
*/
static void CB_Text(Widget W, XtPointer ClientData, XtPointer CallData)
{
if (!LockCallback)
XawListUnhighlight(FileSelector.ListW);
else
LockCallback = False;
}
/* ---------------------------------------------------------------------------
* reads contents of the passed directory into the list
* or calls an external command to create the list
*/
static int FillLists(char *DirName)
{
if ((*DirName == '|' && !FillListsFromCommand(DirName)) ||
!FillListsFromDirectory(DirName))
{
/* sort lists by name */
qsort(FileSelector.Entries, FileSelector.Number,
sizeof(char *), CompareFunction);
qsort(DirectorySelector.Entries, DirectorySelector.Number,
sizeof(char *), CompareFunction);
/* update list widgets and current selection */
XawListChange(FileSelector.ListW, FileSelector.Entries,
FileSelector.Number, 0, True);
XawListChange(DirectorySelector.ListW, DirectorySelector.Entries,
DirectorySelector.Number, 0, True);
/* clear input field; update label */
XtVaSetValues(InputW, XtNstring, "", NULL);
XtVaSetValues(CurrentW, XtNlabel, CurrentDir, NULL);
return(0);
}
return(1);
}
/* ----------------------------------------------------------------------
* calls an external command and read its stdout into the list widget;
* external commands starts with '|'
*/
static int FillListsFromCommand(char *Command)
{
FILE *fp;
char line[256];
int i;
/* ignore leading '|', execute command */
if ((fp = popen(Command+1, "r")) == NULL)
{
PopenErrorMessage(Command+1);
return(1);
}
FreeListEntries(&FileSelector);
FreeListEntries(&DirectorySelector);
while (fgets(line, 256, fp))
{
/* ignore newline and carriage return */
for (i = strlen(line)-1; i >= 0 ; i--)
if (line[i] == '\n' || line[i] == '\r')
line[i] = '\0';
else
break;
AddEntryToList(MyStrdup(line, "FillListsFromCommand()"), &FileSelector);
}
if(pclose(fp))
{
FreeListEntries(&FileSelector);
return(1);
}
/* update label */
CurrentDir = Command;
XtVaSetValues(CurrentW, XtNlabel, Command, NULL);
return(0);
}
/* ---------------------------------------------------------------------------
* reads contents of the passed directory into the list
*/
static int FillListsFromDirectory(char *DirName)
{
DIR *dir;
struct dirent *direntry;
struct stat buffer;
char *entry;
/* open directory */
if (ChangeDirectory(DirName))
return(1);
CurrentDir = GetWorkingDirectory();
if ((dir = opendir(CurrentDir)) == NULL)
{
OpendirErrorMessage(CurrentDir);
return(1);
}
/* release memory */
FreeListEntries(&DirectorySelector);
FreeListEntries(&FileSelector);
/* read all entries */
while ((direntry = readdir(dir)) != NULL)
{
/* check if entry is directory ...
* ignore entry on error
*/
if (!stat(direntry->d_name, &buffer))
{
/* add entry to crresponding list */
if (S_ISDIR(buffer.st_mode))
{
/* ignore '.' entry */
if (!strcmp(direntry->d_name, "."))
continue;
/* allocate memory for string plus mark */
entry = MyCalloc(strlen(direntry->d_name)+2,
sizeof(char), "FillListsFromDirectory()");
sprintf(entry, "%s/", direntry->d_name);
AddEntryToList(entry, &DirectorySelector);
}
else
{
entry = MyStrdup(direntry->d_name, "FillListsFromDirectory()");
AddEntryToList(entry, &FileSelector);
}
}
}
closedir(dir);
/* add at least '..' just in case the directory isn't readable */
if (!DirectorySelector.Number)
AddEntryToList(MyStrdup("../", "FillListsFromDirectory()"),
&DirectorySelector);
return(0);
}
/* ----------------------------------------------------------------------
* creates menu-button with entries from PATH information
' 'copy' needs to be static because a pointer to that memory location
* is returned
*/
static Widget CreateMenuFromPath(Widget Parent,
Widget Top, Widget Left,
char * Path)
{
Widget popup,
menubutton,
entry;
char *path;
Boolean first;
static char *copy;
/* create button */
menubutton = XtVaCreateManagedWidget("preset", menuButtonWidgetClass,
Parent,
LAYOUT_TOP,
XtNfromVert, Top,
XtNfromHoriz, Left,
XtNlabel, "click here for preset directories",
XtNmenuName, "preset",
NULL);
/* create a copy of the path; used for passing to callback */
MyFree(©);
copy = MyStrdup(Path, "CreateMenuFromPath()");
/* append menu with paths */
popup = XtVaCreatePopupShell("preset", simpleMenuWidgetClass,
menubutton,
XtNlabel, NULL,
XtNsensitive, True,
NULL);
for (first = True, path = strtok(copy, ":"); path; path = strtok(NULL, ":"))
{
/* copy first path element to CurrentDir */
if (first)
{
CurrentDir= path;
first = False;
}
entry = XtVaCreateManagedWidget("directory", smeBSBObjectClass,
popup,
XtNlabel, path,
XtNsensitive, True,
NULL);
XtAddCallback(entry, XtNcallback, CB_Menu, (XtPointer) path);
}
return(menubutton);
}
/* ---------------------------------------------------------------------------
* creates a selector (list widget managed by a viewport)
*/
static Widget CreateSelector(Widget Parent,
Widget Top, Widget Left,
SelectorTypePtr Selector)
{
Selector->ViewportW=XtVaCreateManagedWidget("viewport", viewportWidgetClass,
Parent,
XtNfromVert, Top,
XtNfromHoriz, Left,
LAYOUT_NORMAL,
XtNallowHoriz, True,
XtNallowVert, True,
XtNuseBottom, True,
NULL);
Selector->ListW = XtVaCreateManagedWidget(Selector->Name, listWidgetClass,
Selector->ViewportW,
XtNdefaultColumns, 1,
XtNforceColumns, True,
NULL);
if (Selector->Callback)
XtAddCallback(Selector->ListW, XtNcallback,
Selector->Callback, Selector->ClientData);
return(Selector->ViewportW);
}
/* ---------------------------------------------------------------------------
* file select box
* a static pointer to the selected file is returned -->
* it's only valid till it's called again
* the directories in the passed path are available from a menu
*/
char *FileSelectBox(char *MessageText, char *DefaultFile, char *Path)
{
Widget popup,
masterform,
last;
char currentdir[MAXPATHLEN+1],
*file;
static char result[MAXPATHLEN+1];
/* save current directory */
strcpy(currentdir, GetWorkingDirectory());
/* create the popup shell */
popup = XtVaCreatePopupShell("popup", transientShellWidgetClass,
Output.Toplevel,
XtNtransientFor, Output.Toplevel,
XtNallowShellResize, True,
XtNmappedWhenManaged, False,
XtNinput, True,
NULL);
/* the form that holds everything */
masterform = XtVaCreateManagedWidget("selectMasterForm", formWidgetClass,
popup,
XtNresizable, True,
NULL);
/* the line which displays the some text */
last = XtVaCreateManagedWidget("comment", labelWidgetClass,
masterform,
LAYOUT_TOP,
XtNlabel, MessageText,
NULL);
/* create a menu button for preset directories, also
* initializes 'CurrentDir'
*/
last = CreateMenuFromPath(masterform, last, NULL,
(Path && *Path) ? Path : ".");
/* the line which displays the current directory */
CurrentW = XtVaCreateManagedWidget("current", labelWidgetClass,
masterform,
XtNresizable, True,
XtNfromVert, last,
LAYOUT_TOP,
NULL);
InputW = XtVaCreateManagedWidget("input", asciiTextWidgetClass,
masterform,
XtNresizable, True,
XtNresize, XawtextResizeWidth,
XtNwrap, XawtextWrapNever,
XtNeditType, XawtextEdit,
XtNfromVert, CurrentW,
LAYOUT_TOP,
NULL);
XtAddCallback(XawTextGetSource(InputW), XtNcallback, CB_Text, NULL);
/* the two selectors and the buttons */
last = CreateSelector(masterform, InputW, NULL, &DirectorySelector);
last = CreateSelector(masterform, InputW, last, &FileSelector);
AddButtons(masterform, last, Buttons, ENTRIES(Buttons));
/* override the translations for the input widget and
* install accelerators for the buttons
* !!! first translations, second accelerators !!!
* additionaly ignore 'spaces' and 'slashes' during input
*/
XtOverrideTranslations(InputW, XtParseTranslationTable(InputTranslations));
XtOverrideTranslations(InputW,
XtParseTranslationTable("<Key>space: no-op()\n <Key>slash: no-op()\n"));
XtInstallAccelerators(InputW, Buttons[0].W);
XtInstallAccelerators(InputW, Buttons[1].W);
/* set keyboard focus to input widget */
XtSetKeyboardFocus(masterform, InputW);
/* install additional accelerators for the default button;
* double click to select
* install translation so that selection still works
*/
XtOverrideTranslations(FileSelector.ListW,
XtParseTranslationTable("<Btn1Down>: Set() Notify()\n"));
XtInstallAccelerators(FileSelector.ListW, Buttons[0].W);
/* read directory structure of current directory
* which was set to the first menu entry from CreateMenuFromPath()
* set text widget to default and reset lock-flag
*/
FillLists(CurrentDir);
SetInputWidget(DefaultFile ? DefaultFile : "");
LockCallback = False;
/* now display dialog and wait for completion */
StartDialog(popup);
DialogEventLoop(&ReturnCode);
/* evaluate selection */
*result = '\0';
if (ReturnCode == OK_BUTTON)
{
XtVaGetValues(InputW, XtNstring, &file, NULL);
/* append result to current directory */
if (file && *file)
if (*CurrentDir != '|')
sprintf(result, "%s/%s", CurrentDir, file);
else
strcpy(result, file);
}
/* remove event handler, dialog, release resources and
* change back to initial directory
*/
EndDialog(popup);
FreeListEntries(&DirectorySelector);
FreeListEntries(&FileSelector);
ChangeDirectory(currentdir);
return(*result ? result : NULL);
}